package com.example.innerclass4.anonymous;


/**
 * 演示匿名内部类的注意事项和使用细节
 */
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        /*
        2.匿名内部类的语法比较奇特，请大家注意，因为匿名内部类既是一个类的定义，同时它本身也是一个对象，因此从语法上看，它既有定义类的特征，也有创建对象的特征，
          对前面代码分析可以看出这个特点，因此可以调用匿名内部类方法。
        3.可以直接访问外部类的所有成员，包含私有的[案例演示]
        4.不能添加访问修饰符，因为它的地位就是一个局部变量。[过]
        5.作用域：仅仅在定义它的方法或代码块中。[过]
        6.匿名内部类---访问---->外部类成员[访问方式：直接访问]
        7.外部其他类---不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)
        8.如果外部类和匿名内部类的成员重名时，匿名内部类访问的话，默认遵循就近原则，如果想访问外部类的成员，则可以使用（外部类名.this.成员）去访问
         */

        Outer05 outer05 = new Outer05();
        outer05.m1();

        //7.外部其他类---不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)
    }
}

class Outer05 {
    private int a = 10;

    public void m1() {
        //创建一个基于类的匿名内部类
        //此时p的 编译类型 -> Person
        //       运行类型 -> Outer05&1
        //4.不能添加访问修饰符，因为它的地位就是一个局部变量
        //5.作用域：仅仅在定义它的方法或代码块中
        Person p = new Person() {
            private int a = 20;

            @Override
            public void hi() {
                //3.可以直接访问外部类的所有成员，包含私有的
                //6.匿名内部类---访问---->外部类成员[访问方式：直接访问]
                //直接访问外部类的私有属性
                System.out.println(a);
                System.out.println("匿名内部类重写了hi方法");

                //8.如果外部类和匿名内部类的成员重名时，匿名内部类访问的话，默认遵循就近原则，如果想访问外部类的成员，则可以使用（外部类名.this.成员）去访问
                System.out.println(a);//因为默认遵守就近原则，所以访问到的是匿名内部类中的a
                //如何访问外部类中的属性
                System.out.println(Outer05.this.a);//这样访问到的就是外部类中的a

            }
        };
        p.hi();//会有动态绑定 ， 因为运行类型是Outer05$1 所以会找到Outer05$1中的方法

        //如果没有重写hi方法
        //此时p1的 编译类型 -> Person
        //        运行类型 -> Person
        Person p1 = new Person() {

        };
        p1.hi();//此时调用的方法就是Person中的hi方法因为，p1的运行类型是Person

        //也可以直接调用，因为匿名内部类本身返回的就是一个对象
        new Person() {
            @Override
            public void hi() {
                System.out.println("匿名内部类又一次的重写了hi方法");
            }
        }.hi();//可以直接调用
        /*
        可以这样理解
        new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类又一次的重写了hi方法");
            }
        }

        上面这一大块，返回的就是一个对象，在使用对象.方法，不就是我们传统的调用方法的形式吗，对象名.方法名

         */

    }
}

class Person {
    public void hi() {
        System.out.println("Person中的hi方法");
    }
}